package base.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用 Condition 使得线程间 协同
 * 多线程 交叉 打印 A B C
 *
 * 知识点：
 * ReentrantLock的 lock 和 unlock流程
 *
 * Author: shen qi han
 * Date: 2022/3/21 下午5:55
 */
public class ConditionMain {

    /**
     * 使用 ReentrantLock中的 condition 用于 唤醒 和 阻塞
     * 代替 Object 方法中的 signal 和 notify
     */
    Lock lock = new ReentrantLock();

    Condition conditionA = lock.newCondition();
    Condition conditionB = lock.newCondition();
    Condition conditionC = lock.newCondition();

    /**
     * 这里做了个测试，如果 不加锁，而是flag用 volatile去修饰，结果是不准确的
     * 因为 关键字只是保证 当前变量的原子操作，不能保证整个 代码块的准确性
     */
//    volatile String flag = "A";
    String flag = "A";

    String loopA = "A";
    String loopB = "B";
    String loopC = "C";

    class MyTask implements Runnable{
        String name = "";
        Condition needWait;
        Condition needNotify;

        public MyTask(String name, Condition needWait, Condition needNotify){
            this.name = name;
            this.needWait = needWait;
            this.needNotify = needNotify;
        }

        @Override
        public void run() {
            try {
                // 获取锁 资源
                lock.lock();
                // name is not correct name
                // then a temp dead while loop
                while(!flag.equals(this.name)){
                    // block
                    // when another thread wake the wait then adjust the flag
                    // if equal correct name then go out the while
                    needWait.await();
                }
                // print current result
                System.out.println(name);
                //  A->B->C->A circle replace
                if(loopA.equals(this.name)){
                    flag = "B";
                }else if(loopB.equals(this.name)){
                    flag = "C";
                }else{
                    flag = "A";
                }
                // wake
                needNotify.signal();
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                // mark need unlock the lock key
                lock.unlock();
            }
        }
    }


    /**
     * 通过 按照 锁住当前Condition 然后唤醒下一个Condition的方式
     * 实现 线程间的 顺序执行
     * 同时采用 flag 变量去 判断当前线程是否是 将要被执行的线程，不是的话 短暂的while循环
     */
    public void testPoolShutDown(){
        int num = 3;
        int loop = 10;
        MyTask task = new MyTask("A", conditionA, conditionB);
        MyTask task2 = new MyTask("B", conditionB, conditionC);
        MyTask task3 = new MyTask("C", conditionC, conditionA);
        ExecutorService pool = Executors.newFixedThreadPool(num * loop);
        for(int i = 0; i < loop; i++){
            pool.submit(task);
            pool.submit(task2);
            pool.submit(task3);
        }
        pool.shutdown();
    }

    public static void main(String[] args) {
        ConditionMain demo = new ConditionMain();
        demo.testPoolShutDown();
    }

}
